# -*- coding: utf-8 -*-
# Vincent Foley-Bourgon (vfoley <at> gmail <dot> com)
# PyoPaint

import wx

import Utils

SHADOW_COLOR = "#cccccc"

class Measure(wx.Panel):
    def __init__(self, parent):
        self.width = 200
        self.height = 200
        self.topLine = 60
        self.interline = 24
        self.shadowPosition = None
        self.positions = [z for z in xrange(self.topLine,
                                            self.topLine+(5*self.interline),
                                            self.interline/2)]
        wx.Panel.__init__(self, parent=parent, size=(self.width, self.height))
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_LEFT_DOWN, self.OnClick)
        self.Bind(wx.EVT_MOTION, self.OnMouseMove)
        self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLoseFocus)
        self.SetBackgroundColour('#ffffff')
        self.notes = [[], [], [], []]


    def _FindQuarter(self, x):
        """Notes can be put at tempo 0, 1, 2, or 3.  Find out
        the tempo at which tempo x belongs."""
        return x / (self.width / 4)

    def _FindNearestPosition(self, x, y):
        """Find the nearest valid position in the measure near (x,y).
        TODO: use rectangles to make the interface 'tighter'."""
        quarter = self._FindQuarter(x)
        yindex = Utils.argmin([abs(z-y) for z in self.positions])
        return (50*quarter + 25, self.positions[yindex])

    def OnClick(self, evt):
        """Add/remove a note in the measure. Clicking on an
        empty space adds a note, clicking on an existing note
        removes it."""
        x, y = evt.GetPosition()
        quarter = self._FindQuarter(x)
        pos = self._FindNearestPosition(x, y)

        if pos in self.notes[quarter]:
            self.notes[quarter].remove(pos)
        else:
            self.notes[quarter].append(pos)
        self.Refresh()

    def OnMouseMove(self, evt):
        """Update the shadowPosition according to the position
        of the mouse."""
        x, y = evt.GetPosition()
        self.shadowPosition = self._FindNearestPosition(x, y)
        self.Refresh()

    def OnLoseFocus(self, evt):
        """When the mouse goes out of the Measure,
        remove the shadowNote."""
        self.shadowPosition = None
        self.Refresh()

    def OnPaint(self, evt):
        """Display the lines,notes and shadow note of a measure."""
        w, _ = self.GetSize()
        dc = wx.PaintDC(self)
        dc.Clear()

        # Draw the lines of the Measure.
        dc.SetPen(wx.Pen('black', 2))
        dc.DrawLine(0, self.topLine, 0, self.topLine+(4*self.interline))
        dc.DrawLine(w, self.topLine, w, self.topLine+(4*self.interline))
        for i in xrange(self.topLine,
                        self.topLine+(5*self.interline),
                        self.interline):
            dc.DrawLine(0, i, w, i)

        # Draw the shadow note if it exists.
        if self.shadowPosition is not None:
            dc.SetPen(wx.Pen(SHADOW_COLOR, 1))
            dc.SetBrush(wx.Brush(SHADOW_COLOR))
            dc.DrawCircle(self.shadowPosition[0], self.shadowPosition[1], 10)

        # Draw the notes.
        dc.SetPen(wx.Pen('black', 1))
        dc.SetBrush(wx.Brush('black'))
        for notes in self.notes:
            for x, y in notes:
                dc.DrawCircle(x, y, 10)
